package com.inspection.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.inspection.constant.ModelNameEnum;
import com.inspection.dao.InspectionBranchDao;
import com.inspection.dao.InspectionDepartmentDao;
import com.inspection.dao.InspectionNoticePoliticsDao;
import com.inspection.dao.InspectionNoticeViolationDao;
import com.inspection.entity.*;
import com.inspection.model.dto.InspectPoliticsNoticeDTO;
import com.inspection.model.dto.InspectPoliticsNoticeQueryDTO;
import com.inspection.model.dto.InspectViolationNoticeDTO;
import com.inspection.model.dto.InspectViolationNoticeQueryDTO;
import com.inspection.model.vo.InspectNoticeDefaultVO;
import com.inspection.service.FileService;
import com.inspection.service.InspectionNoticeService;
import com.inspection.support.*;
import com.inspection.support.auth.AuthHolder;
import com.inspection.support.model.BusinessBaseException;
import org.apache.commons.io.FileUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class InspectionNoticeServiceImpl implements InspectionNoticeService {

    @Autowired
    private InspectionNoticeViolationDao inspectionNoticeViolationDao;

    @Autowired
    private InspectionNoticePoliticsDao inspectionNoticePoliticsDao;

    @Autowired
    private InspectionDepartmentDao inspectionDepartmentDao;
    @Autowired
    private InspectionBranchDao inspectionBranchDao;
    @Autowired
    private FileService fileService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveViolationNotice(InspectViolationNoticeDTO save) {

        AssertUtils.nonNull(save.getBranchId(),"支部不能为空！");

        //校验编号是否重复
        InspectionNoticeViolationDO noticeQuery = new InspectionNoticeViolationDO();
        noticeQuery.setNoticeWord(save.getNoticeWord());
        noticeQuery.setNoticeNumber(save.getNoticeNumber());
        Optional<InspectionNoticeViolationDO> word = inspectionNoticeViolationDao.findOne(Example.of(noticeQuery));
        if(word.isPresent()){
            throw new BusinessBaseException("编号重复");
        }


        InspectionNoticeViolationDO  newViolaNoticeDO = new InspectionNoticeViolationDO();
        BeanUtils.copyProperties(save,newViolaNoticeDO);
        newViolaNoticeDO.setNoticeWord(save.getNoticeWord());
        newViolaNoticeDO.setNoticeNumber(save.getNoticeNumber());

        Optional<InspectionBranchDO> branchOp = inspectionBranchDao.findById(save.getBranchId());
        newViolaNoticeDO.setBranchId(save.getBranchId());
        newViolaNoticeDO.setBranchName(branchOp.get().getBranchName());

        //如果存在部門信息 組裝部門信息d
        String deptNames="";
        if(!CollectionUtils.isEmpty(save.getDeptList())){
            List<InspectionDepartmentDO> depts = inspectionDepartmentDao.findAllById(save.getDeptList());
            newViolaNoticeDO.setDeptInfo(JSONObject.toJSONString(depts));
            deptNames=   depts.stream().map(d->d.getDeptName()).collect(Collectors.joining(","));

        }
        newViolaNoticeDO.setIsDel(0);
        newViolaNoticeDO.setOperateDate(new Date());


        //异步生成 告知书 todo

        String fileName=newViolaNoticeDO.getNoticeWord()+"-"+newViolaNoticeDO.getNoticeNumber()+".docx";
        String title=newViolaNoticeDO.getBranchName()+"-"+deptNames;

        Calendar c1= Calendar.getInstance();
        c1.setTime(newViolaNoticeDO.getViolationDate());

        Calendar c2= Calendar.getInstance();
        c2.setTime(newViolaNoticeDO.getCorrectDateEnd());


        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("noticeWord",newViolaNoticeDO.getNoticeWord());
        paramMap.put("noticeNumber",newViolaNoticeDO.getNoticeNumber());
        paramMap.put("title",title);
        paramMap.put("violationPersonName",newViolaNoticeDO.getViolationPersonName());
        paramMap.put("violationMonth",String.valueOf(c1.get(Calendar.MONTH)+1));
        paramMap.put("violationDay",String.valueOf(c1.get(Calendar.DATE)));
        paramMap.put("violationContent",newViolaNoticeDO.getViolationContent());
        paramMap.put("correctMonth",String.valueOf(c2.get(Calendar.MONTH)+1));
        paramMap.put("correctDay",String.valueOf(c2.get(Calendar.DATE)));

        Long fileId = generateNoticeFile("correct_notice", fileName, paramMap);

        newViolaNoticeDO.setNoticeFileId(fileId);

        SysUserDO sysUser = AuthHolder.getSysUser();
        newViolaNoticeDO.setOperateUserId(sysUser.getId());
        newViolaNoticeDO.setOperateUserName(sysUser.getUserName());
        inspectionNoticeViolationDao.saveAndFlush(newViolaNoticeDO);



    }

    @Override
    public Page<InspectionNoticeViolationDO> pageViolationNotice(InspectViolationNoticeQueryDTO page) {
        Sort sort = SortHelper.buildSort(page);
        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);


        Page<InspectionNoticeViolationDO> vPage = inspectionNoticeViolationDao.findAll(new Specification<InspectionNoticeViolationDO>() {
            @Override
            public Predicate toPredicate(Root<InspectionNoticeViolationDO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = Lists.newArrayList();
                predicates.add(criteriaBuilder.equal(root.get("isDel"), 0));

                if (!StringUtils.isEmpty(page.getNoticeWord())) {
                    predicates.add(criteriaBuilder.like(root.get("noticeWord"), "%"+page.getNoticeWord()+"%"));
                }
                if (!StringUtils.isEmpty(page.getNoticeNumber())) {
                    predicates.add(criteriaBuilder.like(root.get("noticeNumber"),"%"+ page.getNoticeNumber()+"%"));
                }
                if (!StringUtils.isEmpty(page.getViolationPersonName())) {
                    predicates.add(criteriaBuilder.like(root.get("violationPersonName"), "%"+page.getViolationPersonName()+"%"));
                }
                if (!StringUtils.isEmpty(page.getViolationDate())) {
                    predicates.add(criteriaBuilder.equal(root.get("violationDate"), page.getViolationDate()));
                }

                if (!StringUtils.isEmpty(page.getViolationDateStart())) {
                    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("violationDate"), page.getViolationDateStart()));
                }
                if (!StringUtils.isEmpty(page.getViolationDateEnd())) {
                    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("violationDate"), page.getViolationDateEnd()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        },pageable);

        for (InspectionNoticeViolationDO inspectionNoticeViolationDO : vPage.getContent()) {
            String deptInfo = inspectionNoticeViolationDO.getDeptInfo();
            if(!StringUtils.isEmpty(deptInfo)){
                List<InspectionDepartmentDO> departmentDOS = JSONObject.parseArray(deptInfo, InspectionDepartmentDO.class);
                inspectionNoticeViolationDO.setDeptNames(departmentDOS.stream().map(d->d.getDeptName()).collect(Collectors.joining(",")));
            }
        }
        return vPage;
    }

    @Override
    public InspectNoticeDefaultVO getMaxViolationNotice() {
        Sort sort = new Sort(Sort.Direction.DESC, "noticeWord","noticeNumber");
        InspectionNoticeViolationDO param = new InspectionNoticeViolationDO();
        param.setIsDel(0);

        List<InspectionNoticeViolationDO> vos = inspectionNoticeViolationDao.findAll(Example.of(param),sort);
        if(CollectionUtils.isEmpty(vos)){
            Calendar cl = Calendar.getInstance();
            cl.setTime(new Date());
            return InspectNoticeDefaultVO.builder()
                    .word(String.valueOf(cl.get(Calendar.YEAR)))
                    .number("001")
                    .build();
        }
        InspectionNoticeViolationDO inspectionNoticeViolationDO = vos.get(0);
        String noticeNumber = inspectionNoticeViolationDO.getNoticeNumber();
        int i = Integer.parseInt(noticeNumber);


        return InspectNoticeDefaultVO.builder()
                .word(inspectionNoticeViolationDO.getNoticeWord())
                .number(NoticeUtils.addZeroForNum(String.valueOf(++i),3))
                .build();
    }









    @Override
    public void savePoliticsNotice(InspectPoliticsNoticeDTO save) {
        AssertUtils.nonNull(save.getBranchId(),"支部不能为空！");

        //校验编号是否重复
        InspectionNoticePoliticsDO noticeQuery = new InspectionNoticePoliticsDO();
        noticeQuery.setNoticeWord(save.getNoticeWord());
        noticeQuery.setNoticeNumber(save.getNoticeNumber());
        Optional<InspectionNoticePoliticsDO> word = inspectionNoticePoliticsDao.findOne(Example.of(noticeQuery));
        if(word.isPresent()){
            throw new BusinessBaseException("编号重复");
        }


        InspectionNoticePoliticsDO  newPoliticsDO = new InspectionNoticePoliticsDO();
        BeanUtils.copyProperties(save,newPoliticsDO);
        newPoliticsDO.setNoticeWord(save.getNoticeWord());
        newPoliticsDO.setNoticeNumber(save.getNoticeNumber());

        Optional<InspectionBranchDO> branchOp = inspectionBranchDao.findById(save.getBranchId());
        newPoliticsDO.setBranchId(save.getBranchId());
        newPoliticsDO.setBranchName(branchOp.get().getBranchName());

        //如果存在部門信息 組裝部門信息d
        String deptNames="";
        if(!CollectionUtils.isEmpty(save.getDeptList())){
            List<InspectionDepartmentDO> depts = inspectionDepartmentDao.findAllById(save.getDeptList());
            newPoliticsDO.setDeptInfo(JSONObject.toJSONString(depts));
            deptNames=   depts.stream().map(d->d.getDeptName()).collect(Collectors.joining(","));

        }

        StringBuffer cycleDateBuf = new StringBuffer();
        cycleDateBuf.append(save.getYear());
        String inspectionCycle = save.getInspectionCycle();
        // 1季度 2年
        if("季".equalsIgnoreCase(inspectionCycle)){
            cycleDateBuf.append("-");
            cycleDateBuf.append(save.getInspectionCycleNumber());
        }
        newPoliticsDO.setInspectCycle(inspectionCycle);
        newPoliticsDO.setInspectCycleDate(cycleDateBuf.toString());


        newPoliticsDO.setIsDel(0);
        newPoliticsDO.setOperateDate(new Date());







        String fileName=newPoliticsDO.getNoticeWord()+"-"+newPoliticsDO.getNoticeNumber()+".docx";
        String title=newPoliticsDO.getBranchName()+"-"+deptNames;


        Calendar c2= Calendar.getInstance();
        c2.setTime(newPoliticsDO.getCorrectDateEnd());


        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("noticeWord",newPoliticsDO.getNoticeWord());
        paramMap.put("noticeNumber",newPoliticsDO.getNoticeNumber());
        paramMap.put("title",title);
        paramMap.put("cycleDate",newPoliticsDO.getInspectCycleDate());


        paramMap.put("violationContent",newPoliticsDO.getViolationContent());
        paramMap.put("correctMonth",String.valueOf(c2.get(Calendar.MONTH)+1));
        paramMap.put("correctDay",String.valueOf(c2.get(Calendar.DATE)));

        Long fileId = generateNoticeFile("correct_politics", fileName, paramMap);

        newPoliticsDO.setNoticeFileId(fileId);
        SysUserDO sysUser = AuthHolder.getSysUser();
        newPoliticsDO.setOperateUserId(sysUser.getId());
        newPoliticsDO.setOperateUserName(sysUser.getUserName());
        inspectionNoticePoliticsDao.saveAndFlush(newPoliticsDO);
    }

    @Override
    public Page<InspectionNoticePoliticsDO> pagePoliticsNotice(InspectPoliticsNoticeQueryDTO page) {
        Sort sort = SortHelper.buildSort(page);
        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);


        Page<InspectionNoticePoliticsDO> vPage =  inspectionNoticePoliticsDao.findAll((Specification<InspectionNoticePoliticsDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("isDel"), 0));

            if (!StringUtils.isEmpty(page.getNoticeWord())) {
                predicates.add(criteriaBuilder.like(root.get("noticeWord"), "%"+page.getNoticeWord()+"%"));
            }
            if (!StringUtils.isEmpty(page.getNoticeNumber())) {
                predicates.add(criteriaBuilder.like(root.get("noticeNumber"),"%"+ page.getNoticeNumber()+"%"));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        },pageable);

        for (InspectionNoticePoliticsDO inspectionNoticePoliticsDO : vPage.getContent()) {
            String deptInfo = inspectionNoticePoliticsDO.getDeptInfo();
            if(!StringUtils.isEmpty(deptInfo)){
                List<InspectionDepartmentDO> departmentDOS = JSONObject.parseArray(deptInfo, InspectionDepartmentDO.class);
                inspectionNoticePoliticsDO.setDeptNames(departmentDOS.stream().map(d->d.getDeptName()).collect(Collectors.joining(",")));
            }
        }
        return vPage;
    }

    @Override
    public InspectNoticeDefaultVO getMaxPoliticsNotice() {
        Sort sort = new Sort(Sort.Direction.DESC, "noticeWord","noticeNumber");
        InspectionNoticePoliticsDO param = new InspectionNoticePoliticsDO();
        param.setIsDel(0);

        List<InspectionNoticePoliticsDO> vos = inspectionNoticePoliticsDao.findAll(Example.of(param),sort);
        if(CollectionUtils.isEmpty(vos)){
            Calendar cl = Calendar.getInstance();
            cl.setTime(new Date());
            return InspectNoticeDefaultVO.builder()
                    .word(String.valueOf(cl.get(Calendar.YEAR)))
                    .number("001")
                    .build();
        }

        InspectionNoticePoliticsDO inspectionNoticePoliticsDO = vos.get(0);
        String noticeNumber = inspectionNoticePoliticsDO.getNoticeNumber();
        int i = Integer.parseInt(noticeNumber);


        return InspectNoticeDefaultVO.builder()
                .word(inspectionNoticePoliticsDO.getNoticeWord())
                .number(NoticeUtils.addZeroForNum(String.valueOf(++i),3))
                .build();
    }


    protected  Long generateNoticeFile(String templateName,String targetFileName,Map<String,String> paramMap){
        InputStream inp = DocxUtil.class.getClassLoader().getResourceAsStream(templateName+".docx");

        ByteArrayOutputStream op = null;
        try {
            XWPFDocument xwpfDocument = DocxUtil.processDocVariable(inp, paramMap);

            op = new ByteArrayOutputStream();
            xwpfDocument.write(op);
        } catch (IOException e) {
            e.printStackTrace();
        }


        MultipartFile file = new MockMultipartFile(targetFileName,targetFileName,"application/octet-stream", op.toByteArray());

        return  fileService.addFile(file, ModelNameEnum.INSPECTION.getValue());



    }


}
